﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using InkFx.WinControl.Core;
using InkFx.WinControl.Utils;
using DA = InkFx.WinControl.XIDEAlignment;
using DTGS = InkFx.WinControl.XIDEGroupState;

namespace InkFx.WinControl
{
    /// <summary>
    /// 用于对控件集合进行分组。
    /// </summary>
    [ToolboxItem(false)]
    public class XIDEPopPanel : System.Windows.Forms.Panel
    {
        private XIDEPopPanel(XIDEPage page)
        {
            if (page == null) throw new ArgumentNullException("page");
            if (page.Group == null) throw new ArgumentNullException("page.Group");
            SetStyle(Win32API.ControlStylesUAORSD, true);



            var group = page.Group;
            this.m_BakParent = group.BaseParent;
            this.m_IDEPanel = group.IDEPanel;
            this.m_Group = group;
            this.m_Page = page;

            if (IDEPanel != null) { IDEPanel.SizeChanged += new EventHandler(IDEPanelSizeChanged); }
            Tools.LogDebug(string.Format("XIDEPopPanel 创建: Name='{0}' Type='{1}' ", this.Name, Tools.GetKnowTypeName(this.GetType())));
        }


        #region  静 态 函 数

        /// <summary>
        /// 内部字段
        /// </summary>
        protected static XIDEPopPanel m_ActivePopPanel = null;
        /// <summary>
        /// 静态属性: 全局激活的 弹出面板
        /// </summary>
        public static XIDEPopPanel ActivePopPanel
        {
            get { return m_ActivePopPanel; }
            private set { m_ActivePopPanel = value; }
        }
        /// <summary>
        /// 静态属性: 全局激活的 弹出面板针对的 XIDEGroup
        /// </summary>
        public static XIDEGroup ActivePopGroup
        {
            get
            {
                var panel = ActivePopPanel;
                return panel == null ? null : panel.Group;
            }
        }
        /// <summary>
        /// 静态属性: 全局激活的 弹出面板针对的 XIDEPage
        /// </summary>
        public static XIDEPage ActivePopPage
        {
            get
            {
                var panel = ActivePopPanel;
                return panel == null ? null : panel.Page;
            }
        }



        /// <summary>
        /// 将一个 已经折叠的 XIDEPage 弹出显示
        /// </summary>
        /// <param name="page">需要弹出显示的 page</param>
        public static void PopPage(XIDEPage page)
        {
            var active = ActivePopPanel;
            if (active != null && active.m_Page == page) { DisposeActive(); return; }

            DisposeActive(); //释放已经存在的 弹出面板
            
            //弹出一个新的 弹出面板
            if (page != null && page.Group != null && page.Group.IDEPanel != null)
            {
                new XIDEPopPanel(page).Show();
            }
        }

        /// <summary>
        /// 将当前已经激活的 弹出面板 释放掉
        /// <para>如果存在 激活面板 且成功释放 则返回 true</para>
        /// </summary>
        /// <returns>如果存在 激活面板 且成功释放 则返回 true</returns>
        public static bool DisposeActive()
        {
            var active = ActivePopPanel;
            if (active != null) { active.Dispose(); ActivePopPanel = null; return true; } //如果已经存在 弹出面板, 则将其释放
            return false;
        }

        /// <summary>
        /// 释放除 指定的XIDEGroup 之外的 弹出面板
        /// </summary>
        /// <param name="group">需要排除的 XIDEGroup</param>
        public static void DisposeOther(XIDEGroup group)
        {
            //关闭弹出面板
            var active = XIDEPopPanel.ActivePopPanel;
            if (active != null && active.m_Group != group) { XIDEPopPanel.DisposeActive(); }
        }


        #endregion


        #region  字 段 属 性

        /// <summary>
        /// 内部字段
        /// </summary>
        protected System.Windows.Forms.Control m_BakParent = null;

        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEPanel m_IDEPanel = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEGroup m_Group = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEPage m_Page = null;


        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public System.Windows.Forms.Control BakParent
        {
            get { return m_BakParent; }
        }


        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public XIDEPanel IDEPanel
        {
            get { return m_IDEPanel; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public XIDEGroup Group
        {
            get { return m_Group; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public XIDEPage Page
        {
            get { return m_Page; }
        }

        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public XIDEAlignment Alignment
        {
            get { return m_Group == null ? DA.None : m_Group.Alignment; }
        }


        /// <summary>
        /// 当前控件是否是 横向分割 (本属性是 Orientation 的 中转属性)
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual bool IsHorizontal
        {
            get { var align = this.Alignment; return (align == DA.Top || align == DA.Bottom); }
        }

        /// <summary>
        /// 当前分割线 是否正在移动中 (即; 当前是否正在执行 分割线的拖拽)
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual bool IsSplitMoving
        {
            get { return m_Splitter != null && m_Splitter.IsSplitMoving; }
        }


        #endregion


        #region  函 数 改 写

        /// <summary>
        /// 向用户显示控件。
        /// </summary>
        public virtual new void Show()
        {
            this.Parent = m_IDEPanel;
            this.BringToFront();
            this.ResetRect();
            ActivePopPanel = this;

            m_Group.SetActivePage(m_Page);
            m_Group.BaseParent = this;
            m_Group.m_State = DTGS.Popup;
            m_Group.Visible = true;
            m_Group.Focus();
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.HandleCreated 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
        }



        /// <summary>
        /// 引发 System.Windows.Forms.Control.Paint 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.PaintEventArgs。</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                base.OnPaint(e);
                if (this.IsArgumentInvalid()) return;

                bool debug = false;
                if (debug)
                {
                    #region  调试重绘

                    GUIHelper.FillBack(e.Graphics, GUIHelper.GetRandomColor(100), this.RectContent, true);
                    GUIHelper.FillBack(e.Graphics, GUIHelper.GetRandomColor(100), this.RectSplit, true);

                    #endregion
                }
                else
                {
                    #region  正式重绘

                    DrawSplitter();

                    #endregion
                }
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "改写 XIDEPopPanel.OnPaint(PaintEventArgs e) 发生错误"); }
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.SizeChanged 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            this.ResetRect();
            base.OnSizeChanged(e);
        }


        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseMove 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (this.IsArgumentInvalid()) return;


            var align = this.Alignment;
            if (IsSplitMoving)
            {
                SetCursor((align == DA.Top || align == DA.Bottom) ? Cursors.HSplit : Cursors.VSplit);
                DrawSplitter();
            }
            else
                SetCursor(RectSplit.Contains(e.Location) ? ((align == DA.Top || align == DA.Bottom) ? Cursors.HSplit : Cursors.VSplit) : Cursors.Default);
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseLeave 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.EventArgs。</param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (this.IsArgumentInvalid()) return;
            SetCursor(Cursors.Default);
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseDown 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (this.IsArgumentInvalid()) return;

            var rectangle = this.RectSplit;
            if (rectangle.Contains(e.Location)) { BeginSplitter(this.RectSplitScreenRange, rectangle); }
        }
        /// <summary>
        /// 引发 System.Windows.Forms.Control.MouseUp 事件。
        /// </summary>
        /// <param name="e">包含事件数据的 System.Windows.Forms.MouseEventArgs。</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (this.IsArgumentInvalid()) return;

            var split = EndSplitter();
            DoSplitMoved(split);
        }
        
        #endregion




        #region  绘 制 分 割 线

        /// <summary>
        /// 内部字段
        /// </summary>
        protected SplitterForm m_Splitter;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Cursor m_BakCursor = null;


        /// <summary>
        /// 
        /// </summary>
        /// <param name="cursor">Type: System.Windows.Forms.Cursor</param>
        protected void SetCursor(System.Windows.Forms.Cursor cursor)
        {
            if (m_BakCursor == null) m_BakCursor = base.Cursor ?? Cursors.Default;
            var baseCursor = base.Cursor;
            if (baseCursor != null && baseCursor != cursor)
                base.Cursor = cursor ?? m_BakCursor;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="info">Type: SplitInfo</param>
        protected void DoSplitMoved(SplitInfo info)
        {
            var diff = info.Diff;
            if (diff.X == 0 && diff.Y == 0) return;
            if (this.IsArgumentInvalid()) return;

            var page = this.Page;
            var align = this.Alignment;

            var size = page.BakPopSize;
            if (align == DA.Top) { page.BakPopSize = new Size(size.Width, size.Height + diff.Y); }
            else if (align == DA.Bottom) { page.BakPopSize = new Size(size.Width, size.Height - diff.Y); }
            else if (align == DA.Left) { page.BakPopSize = new Size(size.Width + diff.X, size.Height); }
            else if (align == DA.Right) { page.BakPopSize = new Size(size.Width - diff.X, size.Height); }

            this.ResetRect();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="rectScreenRange">Type: Rectangle</param>
        /// <param name="rectSplit">Type: Rectangle</param>
        protected virtual void BeginSplitter(Rectangle rectScreenRange, Rectangle rectSplit)
        {
            if (this.IsArgumentInvalid()) return;
            
            var rectSplit2 = this.RectangleToScreen(rectSplit);
            var clip = Win32API.GetClipRegion(this.IDEPanel);

            if (m_Splitter == null) { m_Splitter = SplitterForm.BeginSplitter(this.FindForm(), this.IsHorizontal, rectScreenRange, rectSplit2, clip); }
            m_Splitter.ShowSplitter(rectSplit2, clip);
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual void DrawSplitter()
        {
            if (m_Splitter != null) m_Splitter.ShowSplitter();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual SplitInfo EndSplitter()
        {
            if (m_Splitter != null)
            {
                var result = m_Splitter.EndSplitter();
                m_Splitter = null;
                return result;
            }
            return SplitInfo.Empty;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual SplitInfo GetSplitInfo()
        {
            var info = (m_Splitter != null) ? m_Splitter.GetSplitInfo() : SplitInfo.Empty;
            var info2 = new SplitInfo(this.RectangleToClient(info.Start), this.RectangleToClient(info.End));
            return info2;
        }


        #endregion




        #region  坐 标 区 域

        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectSplit = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectContent = Rectangle.Empty;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected Rectangle m_RectSplitScreenRange = Rectangle.Empty;


        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectSplit
        {
            get { return m_RectSplit; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectContent
        {
            get { return m_RectContent; }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Always)]
        public virtual Rectangle RectSplitScreenRange
        {
            get { return m_RectSplitScreenRange; }
        }


        /// <summary>
        /// 
        /// </summary>
        public virtual void ResetRect()
        {
            if (this.IsArgumentInvalid()) return;

            var idePanel = this.IDEPanel;
            var ideGroup = this.Group;
            var idePage = this.Page;
            var align = this.Alignment;
            var split = XIDEPanel.SPLIT_SIZE;
            var rect = idePanel.RectInner;
            var dockWidth = rect.Width;
            var dockHeight = rect.Height;
            var pageSize = idePage.BakPopSize;



            var bounds = Rectangle.Empty;
            var padding = Padding.Empty;
            var rectSplit = Rectangle.Empty;
            var rectContent = Rectangle.Empty;
            if (align == DA.Left)
            {
                padding = new Padding(0, 0, split, 0);
                bounds = new Rectangle(rect.X + 0, rect.Y + 0, pageSize.Width, dockHeight);
                rectSplit = new Rectangle(bounds.Width - split, 0, split, bounds.Height);
                rectContent = new Rectangle(0, 0, bounds.Width - split, bounds.Height);
            }
            else if (align == DA.Right)
            {
                padding = new Padding(split, 0, 0, 0);
                bounds = new Rectangle(rect.X + (dockWidth - pageSize.Width), rect.Y + 0, pageSize.Width, dockHeight);
                rectSplit = new Rectangle(0, 0, split, bounds.Height);
                rectContent = new Rectangle(split, 0, bounds.Width - split, bounds.Height);
            }
            else if (align == DA.Top)
            {
                padding = new Padding(0, 0, 0, split);
                bounds = new Rectangle(rect.X + 0, rect.Y + 0, dockWidth, pageSize.Height);
                rectSplit = new Rectangle(0, bounds.Height - split, bounds.Width, split);
                rectContent = new Rectangle(0, 0, bounds.Width, bounds.Height - split);
            }
            else if (align == DA.Bottom)
            {
                padding = new Padding(0, split, 0, 0);
                bounds = new Rectangle(rect.X + 0, rect.Y + (dockHeight - pageSize.Height), dockWidth, pageSize.Height);
                rectSplit = new Rectangle(0, 0, bounds.Width, split);
                rectContent = new Rectangle(0, split, bounds.Width, bounds.Height - split);
            }


            const int minSize = XIDEPanel.POP_SPLIT_PANEL_MIN_SIZE;
            var rectRange0 = this.IsHorizontal ? new Rectangle(rect.X, rect.Y + minSize, rect.Width, rect.Height - minSize - minSize) : new Rectangle(rect.X + minSize, rect.Y, rect.Width - minSize - minSize, rect.Height);
            var rectRange1 = idePanel.RectangleToScreen(rectRange0);
            //Console.WriteLine("Range: " + rectRange1);


            this.Bounds = bounds;
            base.Padding = padding;
            this.m_RectSplit = rectSplit;
            this.m_RectContent = rectContent;
            this.m_RectSplitScreenRange = rectRange1;
            ideGroup.Bounds = m_RectContent;
        }



        #endregion


        #region  其 他 函 数


        /// <summary>
        /// 返回一个 bool 值, 标识 当前对象的 参数已经无效 (当本函数返回true时, 建议不要再执行任何逻辑)
        /// </summary>
        /// <returns>如果参数已经无效 则返回 true</returns>
        protected bool IsArgumentInvalid()
        {
            var idePanel = this.IDEPanel;
            var ideGroup = this.Group;
            var idePage = this.Page;
            if (idePanel == null || ideGroup == null || idePage == null) return true;

            return false;
        }

        /// <summary>
        /// 当外围 XIDEPanel 尺寸发生改变时 执行本事件函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void IDEPanelSizeChanged(object sender, EventArgs e)
        {
            this.ResetRect();
        }
        

        /// <summary>
        /// 资源释放, 各归各位
        /// </summary>
        /// <param name="disposing">为 true 则释放托管资源和非托管资源；为 false 则仅释放非托管资源。</param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                var group = this.m_Group;
                var bakParent = this.m_BakParent;
                if (group != null) { group.BaseParent = bakParent; }


                this.m_BakParent = null;
                this.m_IDEPanel = null;
                this.m_Group = null;
                this.m_Page = null;

                if (m_ActivePopPanel == this) m_ActivePopPanel = null;
                base.Dispose(disposing);
                Tools.LogDebug(string.Format("XIDEPopPanel 销毁: Name='{0}' Text='{1}' Type='{2}' ", this.Name, this.Text, Tools.GetKnowTypeName(this.GetType())));
            }
            catch (Exception ex) { Tools.LogWarn2(ex, "可忽略的偶发错误"); }
        }

        #endregion

    }
}
